package com.ete.service.service.version

import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInstaller
import android.content.pm.PackageInstaller.SessionParams
import android.net.ConnectivityManager
import android.os.Build
import android.os.Build.VERSION.SDK_INT
import android.view.View
import android.view.Window
import com.blankj.utilcode.util.*
import com.ete.service.callback.version.AutoCheckCallback
import com.ete.service.callback.version.IVersionCallback
import com.ete.service.callback.version.ManualCheckCallback
import com.ete.service.callback.version.SilentCheckCallback
import com.ete.service.dialog.CommonDialog
import com.ete.service.dialog.MiniLoadingDialog
import com.ete.service.dialog.version.CheckVersionDialog
import com.ete.service.entry.dialog.CommonDialogEntry
import com.ete.service.entry.version.VersionEntry
import com.ete.service.entry.version.VersionUpgradeInfo
import com.ete.service.manager.ManagerConstant
import com.ete.service.manager.log.LogManager
import com.ete.service.manager.version.VersionManager
import com.ete.service.net.api.ServiceApi
import com.ete.service.net.bean.BaseResponse
import com.ete.service.net.exception.ExceptionTranslate
import com.ete.service.net.http.RetrofitClient
import com.ete.service.service.R
import com.ete.service.service.version.processor.VersionProcessor
import com.ete.service.service.version.sp.VersionSpUtil
import com.ete.service.util.log.EteLog
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.io.File
import java.io.FileInputStream
import java.io.IOException


/**
 * Author:LiXian
 * <p>
 * Desc:版本辅助类
 * Version:1.0
 * date 2023/12/19 9:20
 */
object VersionHelper {

    private lateinit var mVersionEntry: VersionEntry
    private lateinit var mProcessor: VersionProcessor

    private var mNetworkListener: NetworkUtils.OnNetworkStatusChangedListener? = null

    private val mAppVersion: String by lazy { AppUtils.getAppVersionName() }

    /**
     * 初始化
     */
    @JvmStatic
    fun init(versionEntry: VersionEntry) {
        this.mVersionEntry = versionEntry
        mProcessor = VersionProcessor(mVersionEntry)
        FileUtils.createOrExistsDir(mVersionEntry.mAppPathDir)
        registerNetworkStatusChangedListener()
    }

    /**
     * 注册网络改变监听
     */
    @JvmStatic
    fun registerNetworkStatusChangedListener() {
        if (mNetworkListener == null) {
            mNetworkListener = object : NetworkUtils.OnNetworkStatusChangedListener {
                override fun onDisconnected() {
                    EteLog.d(VersionManager.TAG, "网络已断开")
                }

                override fun onConnected(networkType: NetworkUtils.NetworkType?) {
                    EteLog.d(VersionManager.TAG, "网络已连接，开始检查新版本")
                    ThreadUtils.runOnUiThreadDelayed({ autoCheckNewVersion() }, 3000)
                }
            }
        }
        val isRegister = NetworkUtils.isRegisteredNetworkStatusChangedListener(mNetworkListener)
        if (!isRegister) {
            EteLog.d(VersionManager.TAG, "注册网络改变监听")
            NetworkUtils.registerNetworkStatusChangedListener(mNetworkListener)
        } else {
            EteLog.d(VersionManager.TAG, "网络状态改变监听已注册")
        }
    }

    /**
     * 注销网络改变监听
     */
    @JvmStatic
    fun unRegisterNetworkStatusChangedListener() {
        if (mNetworkListener == null) return
        NetworkUtils.unregisterNetworkStatusChangedListener(mNetworkListener)
    }

    /**
     * 自动检查新版本
     */
    @JvmStatic
    fun autoCheckNewVersion(mCallback: AutoCheckCallback? = null) {
        val mAutoCheckCallback = mCallback ?: object : AutoCheckCallback() {
            override fun isUpgradeNotice(isUpgrade: Boolean) {
                EteLog.d(VersionManager.TAG, "自动检查新版本，是否升级isUpgrade:[$isUpgrade]")
            }

            override fun cancelUpgrade() {
                EteLog.d(VersionManager.TAG, "取消升级")
            }
        }
        val mNetwork = Utils.Consumer<Boolean> {
            if (it) {
                EteLog.d(VersionManager.TAG, "自动检查新版本")
                startCheckNewVersion(mAutoCheckCallback)
            } else {
                EteLog.d(VersionManager.TAG, "自动检查新版本，无网络！！")
            }
        }
        NetworkUtils.isAvailableAsync(mNetwork)
    }

    /**
     * 手动版本检查
     */
    @JvmStatic
    fun manualCheckNewVersion(mCallback: ManualCheckCallback? = null) {
        EteLog.d(VersionManager.TAG, "手动检查新版本")
        val mManualCheckCallback = mCallback ?: object : ManualCheckCallback() {
            override fun isNewVersion(isNewVersion: Boolean) {
                EteLog.d(VersionManager.TAG, "手动检查新版本isNewVersion:[$isNewVersion]")
            }

            override fun cancelUpgrade() {
                EteLog.d(VersionManager.TAG, "手动检查新版本，取消升级")
            }
        }
        val mContext = ActivityUtils.getTopActivity()
        if (mContext == null) {
            ToastUtils.showShort(R.string.version_last_version)
            return
        }
        val mMiniDialog = MiniLoadingDialog.getMiniDialog(mContext, R.string.upload_check_network)
        mMiniDialog.show()
        CoroutineScope(Dispatchers.IO).launch {
            val mType = NetworkUtils.getNetworkType()
            withContext(Dispatchers.Main) {
                mMiniDialog.dismiss()
                withContext(Dispatchers.Main) {
                    if (mType == NetworkUtils.NetworkType.NETWORK_NO) {
                        EteLog.d(LogManager.TAG, "网络不可用！")
                        ToastUtils.showShort(R.string.upload_not_network)
                    } else {
                        startCheckNewVersion(mManualCheckCallback)
                    }
                }
            }
            cancel()
        }
    }

    /**
     * 静默版本检查
     */
    @JvmStatic
    fun silentCheckNewVersion(mCallback: SilentCheckCallback) {
        EteLog.d(VersionManager.TAG, "静默检查新版本")
        val mNetwork = Utils.Consumer<Boolean> {
            if (it) {
                startCheckNewVersion(mCallback)
            }
        }
        NetworkUtils.isAvailableAsync(mNetwork)
    }

    @JvmStatic
    private fun startCheckNewVersion(iVersionCallback: IVersionCallback) {
        iVersionCallback.onStart()
        val mCallback = object : Callback<BaseResponse<VersionUpgradeInfo>> {
            override fun onResponse(
                    call: Call<BaseResponse<VersionUpgradeInfo>>,
                    response: Response<BaseResponse<VersionUpgradeInfo>>?
            ) {
                if (response == null) {
                    iVersionCallback.onError("请求服务器错误")
                    return
                }
                if (!response.isSuccessful) {
                    iVersionCallback.onError("请求服务器错误: ${response.message()}")
                    return
                }
                val result = response.body()
                if (result == null) {
                    iVersionCallback.onError("服务器响应为空")
                    return
                }
                val isSuccess = result.succ
                if (isSuccess == null || !isSuccess) {
                    iVersionCallback.onError(result.msg ?: "请求服务器错误")
                    return
                }
                val dataInfo = result.data
                if (dataInfo == null || !isHadNewVersion(dataInfo)) {
                    iVersionCallback.onNoNewVersion()
                    return
                }
                EteLog.d(VersionManager.TAG, "有新版本dataInfo:[$dataInfo]")
                iVersionCallback.onVersionInfo(dataInfo)
            }

            override fun onFailure(call: Call<BaseResponse<VersionUpgradeInfo>>, t: Throwable) {
                val exception = ExceptionTranslate.translateException(t)
                exception.printStackTrace()
                iVersionCallback.onError("查询版本失败:${exception.message}")
            }
        }
        RetrofitClient.createService(ServiceApi::class.java)
            .getLatestVersion(mVersionEntry.mAppType, mAppVersion).enqueue(mCallback)
    }

    /**
     * 是否提醒升级（强制升级或强提醒升级）
     */
    @JvmStatic
    fun isNoticeUpgrade(mUpgradeInfo: VersionUpgradeInfo): Boolean {
        if (mUpgradeInfo.url.isNullOrEmpty()) {
            EteLog.d(VersionManager.TAG, "APP下载链接为null")
            return false
        }
        val isForceUpgrade = ManagerConstant.RELEASE_TYPE_VERSION_FORCE == mUpgradeInfo.releaseType
        EteLog.d(VersionManager.TAG, "是否强制升级isForceUpgrade:[$isForceUpgrade]")
        val isStrongNotice = ManagerConstant.RELEASE_TYPE_VERSION_STRONG == mUpgradeInfo.releaseType
                && VersionSpUtil.isNoticeUpgrade(mUpgradeInfo.version ?: "")
        EteLog.d(VersionManager.TAG, "是否强提醒升级isStrongNotice:[$isStrongNotice]")
        return isForceUpgrade || isStrongNotice //|| mVersionEntry.isSilentInstall
    }

    /**
     * 是否有新版本
     */
    @JvmStatic
    fun isHadNewVersion(mVersionUpgradeInfo: VersionUpgradeInfo): Boolean {
        val version = mVersionUpgradeInfo.version
        if (version.isNullOrEmpty()) return false
        val currentVersions = AppUtils.getAppVersionName().split(".")
        val versions = version.split(".")
        try {
            currentVersions.forEachIndexed { index, _ ->
                if (index > versions.size - 1) {
                    return false
                }
                // 当前版本大于查询版本，不是新版本
                if (currentVersions[index].toInt() > versions[index].toInt()) {
                    return false
                }
                // 当前版本小于查询版本，是新版本
                if (currentVersions[index].toInt() < versions[index].toInt()) {
                    return true
                }
            }
            // 版本长度一致且前面匹配都不成功, 则说明版本一致，没有新版本
            if (currentVersions.size >= versions.size) {
                return false
            }
            // 如果前面匹配一致，且新版本的版本长度比旧版本长，则认为是新版本
            return true
        } catch (e: Exception) {
            EteLog.i(VersionManager.TAG,
                    "Compare app version failed, currentVersion $currentVersions, newVersion:$version, error:${e.message}"
            )
        }
        return false
    }

    /**
     * 显示升级提示框
     */
    @JvmStatic
    fun showUpgradeDialog(mUpgradeInfo: VersionUpgradeInfo, mCancelCallback: (() -> Unit)? = null) {
        EteLog.d(VersionManager.TAG, "显示升级提示框mUpgradeInfo:[$mUpgradeInfo]")
        mProcessor.showUpgradeDialog(mUpgradeInfo, mCancelCallback)
    }

    /**
     * 显示检测升级提示框
     */
    @JvmStatic
    fun showCheckVersionDialog(): CheckVersionDialog? {
        EteLog.d(VersionManager.TAG, "显示检测升级提示框")
        return mProcessor.showCheckVersionDialog()
    }

    /**
     * 显示通用提示框
     */
    @JvmStatic
    fun showCommonDialog(mEntry: CommonDialogEntry): CommonDialog {
        EteLog.d(VersionManager.TAG, "显示通用提示框")
        return mProcessor.showCommonDialog(mEntry)
    }

    /**
     * 检查安装App权限
     */
    @JvmStatic
    fun isInstallPermission(): Boolean {
        val isInstallPermission = SDK_INT >= Build.VERSION_CODES.O &&
                Utils.getApp().packageManager.canRequestPackageInstalls()
        EteLog.d(VersionManager.TAG, "检查安装App权限isInstallPermission:[$isInstallPermission]")
        return isInstallPermission
    }

    /**
     * 安装App
     */
    @JvmStatic
    fun installApp(mApkPath: String) {
        EteLog.d(VersionManager.TAG, "安装App mApkPath:[$mApkPath]")
        if (mVersionEntry.isSilentInstall) {
            installClientApp(mApkPath)
        } else {
            AppUtils.installApp(mApkPath)
        }
    }

    @JvmStatic
    fun installClientApp(mApkPath: String) {
        CoroutineScope(Dispatchers.IO).launch {
            var session: PackageInstaller.Session? = null
            try {
                val mAct = ActivityUtils.getTopActivity() ?: return@launch
                //获取PackageInstaller对象
                val packageInstaller: PackageInstaller = mAct.packageManager.packageInstaller
                val params = SessionParams(SessionParams.MODE_FULL_INSTALL)
                //创建一个Session
                val sessionId = packageInstaller.createSession(params)
                //建立和PackageManager的socket通道，Android中的通信不仅仅有Binder还有很多其它的
                session = packageInstaller.openSession(sessionId)
                //将App的内容通过session传输
                addApkToInstallSession(FileUtils.getFileByPath(mApkPath), session)

                val mPendIntent = PendingIntent.getBroadcast(mAct, sessionId,
                        Intent("android.intent.action.PACKAGE_ADDED"),
                        PendingIntent.FLAG_IMMUTABLE)
                val sender = mPendIntent.intentSender
                //开启安装
                session.commit(sender)
            } catch (e: IOException) {
                EteLog.d("Couldn't install package error:[$e]")
            } catch (e: RuntimeException) {
                session?.abandon()
                EteLog.d("RuntimeException error:[$e]")
            } catch (e: Exception) {
                EteLog.d("Exception error:[$e]")
            } finally {
                EteLog.d("安装APK失败")
            }
        }
    }

    @Throws(IOException::class)
    private fun addApkToInstallSession(file: File, session: PackageInstaller.Session) {
        val mOut = session.openWrite("package", 0, file.length())
        val mIn = FileInputStream(file)
        val buffer = ByteArray(65536)
        var n: Int
        while (mIn.read(buffer).also { n = it } >= 0) {
            mOut.write(buffer, 0, n)
        }
        session.fsync(mOut)
        mOut.close()
        mIn.close()
    }

    /**
     * 全屏
     */
    @JvmStatic
    fun fullScreen(window: Window?) {
        if (window == null) {
            return
        }
        window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LOW_PROFILE
                or View.SYSTEM_UI_FLAG_FULLSCREEN
                or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)
    }

    @JvmStatic
    fun isNetworkAvailable(): Boolean {
        val service = Utils.getApp().getSystemService(Context.CONNECTIVITY_SERVICE)
        if (service is ConnectivityManager) {
            val info = service.activeNetworkInfo
            return !(null == info || !info.isAvailable)
        }
        return false
    }

    @JvmStatic
    fun getDialogWidth(rate: Float): Int {
        val mScreenWidth = ScreenUtils.getScreenWidth() - SizeUtils.dp2px(24F)
        val mScreenHeight = ScreenUtils.getScreenHeight() - SizeUtils.dp2px(24F)
        val mWidth: Int = if (mScreenWidth > mScreenHeight) {
            mScreenWidth
        } else {
            mScreenHeight
        }
        val mRateWidth = (mWidth * rate).toInt()
        return if (mRateWidth > mScreenWidth) {
            mScreenWidth
        } else {
            mRateWidth
        }
    }
}